package org.ray.sys;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class CommandUtils
{
	/**
	 * Execute command by java runtime
	 * @param cmdArray      The array containing command and its parameters
	 * @param errorMessage  The buffer save error message from executing the command, null if ignore
	 * @param outputMessage The buffer save output message from executing the command, null if ignore
	 */
	public static void executeCmd(String[] cmdArray, StringBuffer errorMessage, StringBuffer outputMessage)
	{
		executeCmd(cmdArray, null, errorMessage, outputMessage);
	}
	
	public static void executeCmd(String[] cmdArray, String workingDir, StringBuffer errorMessage, StringBuffer outputMessage)
	{
		if (cmdArray == null || cmdArray.length == 0)
		{
			throw new RuntimeException("Command Array cannot be null or empty");
		}
	    
	    Process p = null;
	    
	    StringBuffer sbError = errorMessage;
	    StringBuffer sbOutput = outputMessage;
	    try
        {
			/* Print out the complete command information */
		    StringBuffer cmdInfo = new StringBuffer("Running command:");
		    for (String cmd : cmdArray)
		    {
		    	cmdInfo.append(" ").append(cmd);
		    }
            System.out.println(cmdInfo.toString());

            /* start a process to execute the command */
			Runtime rt = Runtime.getRuntime();
			
			if (workingDir == null)
			{
				p = rt.exec(cmdArray);
			}
			else
			{
				p = rt.exec(cmdArray, null, new File(workingDir));
			}
            
            /* Read the error message into buffer */
            if (errorMessage == null)
            {
            	sbError = new StringBuffer();
            }

            /* Read the output message into buffer */
            if (outputMessage == null)
            {
            	sbOutput = new StringBuffer();
            }
            StreamGobbler errorStreamGobbler = new StreamGobbler(p.getErrorStream(), sbError);
            StreamGobbler outputStreamGobbler = new StreamGobbler(p.getInputStream(), sbOutput);
            errorStreamGobbler.start();
            outputStreamGobbler.start();
            
            /* Wait until the process is finished */
            try 
            {
				p.waitFor();
			}
            catch (InterruptedException e) 
			{
            	sbError.append("Interrupted");
            	outputStreamGobbler.interrupt();
            	errorStreamGobbler.interrupt();
				e.printStackTrace();
			}
        }
	    catch (IOException e)
        {            
            e.printStackTrace();	            
        }
    	finally
    	{    		
    		if (p != null)
    		{
    			p.destroy();
    		}
    	}
    	
    	// print output and error message
    	System.out.println(sbOutput);
    	System.err.println(sbError);
	}
	
	public static void executeCmdUnderBash(String[] cmdArray, String workingDir, StringBuffer errorMessage, StringBuffer outputMessage)
	{
		if (cmdArray == null || cmdArray.length == 0)
		{
			throw new RuntimeException("Command Array cannot be null or empty");
		}
	    
	    Process p = null;
	    
	    StringBuffer sbError = errorMessage;
	    StringBuffer sbOutput = outputMessage;
	    try
        {
			/* Print out the complete command information */
		    StringBuffer cmdInfo = new StringBuffer("Running command:");
		    StringBuffer cmdString = new StringBuffer();
		    for (String cmd : cmdArray)
		    {
		    	cmdString.append(" ").append(cmd);
		    }
		    cmdInfo.append(cmdString.toString());
            System.out.println(cmdInfo.toString());
            
            String[] cmdArrayUnderBash = new String[]
                                                    {
            		"/bin/bash",
            		"-c",
            		cmdString.toString()
                                                    };

            /* start a process to execute the command */
			Runtime rt = Runtime.getRuntime();
			
			if (workingDir == null)
			{
				p = rt.exec(cmdArrayUnderBash);
			}
			else
			{
				p = rt.exec(cmdArrayUnderBash, null, new File(workingDir));
			}
            
            /* Read the error message into buffer */
            if (errorMessage == null)
            {
            	sbError = new StringBuffer();
            }

            /* Read the output message into buffer */
            if (outputMessage == null)
            {
            	sbOutput = new StringBuffer();
            }
            StreamGobbler errorStreamGobbler = new StreamGobbler(p.getErrorStream(), sbError);
            StreamGobbler outputStreamGobbler = new StreamGobbler(p.getInputStream(), sbOutput);
            errorStreamGobbler.start();
            outputStreamGobbler.start();
            
            /* Wait until the process is finished */
            try 
            {
				p.waitFor();
			}
            catch (InterruptedException e) 
			{
            	sbError.append("Interrupted");
            	outputStreamGobbler.interrupt();
            	errorStreamGobbler.interrupt();
				e.printStackTrace();
			}
        }
	    catch (IOException e)
        {            
            e.printStackTrace();	            
        }
    	finally
    	{    		
    		if (p != null)
    		{
    			p.destroy();
    		}
    	}
	}
}

class StreamGobbler extends Thread
{
	private InputStream is;
	private StringBuffer buffer;
	
	StreamGobbler(InputStream is, StringBuffer buffer)
	{
		this.is = is;
		this.buffer = buffer;
	}
	
	public void run()
	{
		work();
	}

	private void work()
	{
		BufferedReader br = null;
		try
		{
			InputStreamReader isr = new InputStreamReader(is);
			br = new BufferedReader(isr);
			String line = null;
			
			while ((line = br.readLine()) != null)
			{
				buffer.append(line).append("\n");
			}
			//System.out.println(buffer.toString());
		}
		catch (IOException ioe)
		{
			// Nothing to do
		}
    	finally
    	{
    		if (br != null)
    		{
    			try 
    			{
    				br.close();
				}
    			catch (IOException e) { }
    		}
    	}
	}
}
